package SIM_trafficInfo;

#Copyright 2006 - 2008 Bernard van de Koppel
#This file is part of Sipman
#Sipman is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#Sipman is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with Sipman.  If not, see <http://www.gnu.org/licenses/>.
#
require Exporter;
use SIM_settings;
use SIM_base;

our @ISA 	= ("Exporter");
our @EXPORT	= qw( processTeardown analyseSyslog
                     );
our @VERSION	= 0.01;			# version number

# include variabeles to be used over the various modules here.
#
#

#my $ipDatabaseDir = $ENV{'SIM_IPDATAB'};
my $debugging = "$ENV{'SIM_DEBUGGING'}" || die "Oops no env found for SIM_DEBUGGING.";

# read known-ports
# known ports are defined to implement directionawareness and resolve a bug in catos, where the firewalls misreports source - dest.
my %knownProts = ();
my @portInfo = split(' ', $SIMparam{'SIMnetflowKnownPorts'});
foreach my $entry (@portInfo) {
  $knownProts{$entry} = "known";
}

sub analyseSyslog {
  #sub to analyse traffic info, called from the traffic analyser and fwrb-analyser.
  my $modToolAction = "@_[0]";
  my $syslogDir = "@_[1]";
  my $device = "@_[2]";
  my $baseSyslogDir = $SIMparam{'SIMsyslogDir'};
  if ( ! -d $baseSyslogDir ) {
    print("Oops, no syslog dir found.");
  } elsif (( "$syslogDir" eq "" ) or ( "$syslogDir" eq "none" )) {
    chdir $baseSyslogDir;
    my @dirEntries = <*>;
    print("<H2>Please select the syslog directory below</H2>");
    foreach my $entry (@dirEntries) {
      print(" <A HREF=$httpScriptName?$modToolAction+$entry>$entry</A> <BR>");
    }
  } elsif (( "$device" eq "" ) and ( -d "$baseSyslogDir/$syslogDir" )) {
    print("<H2>Please select the device below</H2>");
    chdir "$baseSyslogDir/$syslogDir";
    my @dirEntries = <*>;
    foreach my $entry (@dirEntries) {
      print(" <A HREF=$httpScriptName?$modToolAction+$syslogDir+$entry>$entry</A> <BR>");
    }
# } elsif (( "$device" ne "" ) and ( -f "$baseSyslogDir/$syslogDir/$device/all-messages" )) {
  } elsif ( "$device" ne "" ) {
    print("<H2>Analysing syslogfile for $device ($syslogDir).</H2>");
    my $baseDir = "$SIMparam{'SIMtrafficAnalyserDir'}/$syslogDir/$device";
    if ( -d "$baseDir.old" ) {
      print("<BR>Previous old data found, removing it in the background...");
      my $statusDate = printDate( time, "logdate" );
      system(" mv $baseDir.old $baseDir.old.$statusDate ");
      system(" rm -fR $baseDir.old.$statusDate &");
      sleep 2;
    }
#   print("teardownTcp=$baseSyslogDir/$syslogDir/$device/*-302014, teardownUdp=$baseSyslogDir/$syslogDir/$device/*-302014<BR>");
#   my @teardownTcp = <$baseSyslogDir/$syslogDir/$device/*-302014:>;
#   my @teardownUdp = <$baseSyslogDir/$syslogDir/$device/*-302016:>;
#   my @allTeardown = ( @teardownTcp, @teardownUdp );
#   printDebug(0, "analyseSyslog: num allTeardown = $#allTeardown. ");
    my $messageFile = "$baseSyslogDir/$syslogDir/$device/all-messages";
    if ( ! -f $messageFile ) {
      print("<H2>Oops, $messageFile not found.</H2>");
    } elsif ( ! -r $messageFile ) {
      print("Oops, problems reading all-messages for $device.");
    } else {
      if ( -d $baseDir ) { system(" mv $baseDir $baseDir.old "); }
      if ( ! -d "$baseDir/dbase" ) { system(" mkdir -p $baseDir/dbase"); }
      mkdir("$baseDir/source");
      mkdir("$baseDir/dest");
      mkdir("$baseDir/port");
      # read known-ports
      my %knownProts = ();
      my @portInfo = split(' ', $SIMparam{'SIMnetflowKnownPorts'});
      foreach my $entry (@portInfo) {
        $knownProts{$entry} = "known";
      }
      if ( ! -f $messageFile ) {
        print("<H2>Oops, $messageFile not found.</H2>");
      } else {
        printDebug(1, "analyseSyslog messageFile: $messageFile.");
        open( IN, $messageFile );
        my $num = 0;
        my $total = 0;
        my $centos = 0;
        while ( my $line = <IN> ) {
          my @word = split(' ', $line);
          if (( "$word[5]" eq "Teardown" ) and (( "$word[6]" eq "TCP" ) or ( "$word[6]" eq "UDP" )) and ( "$word[16]" ne "0" )) {
            my $date = "$word[1]-$word[2]";
            my $time = substr($word[3], 0, -1);
            my $proto = lc($word[6]);
            my $sourceInfo = $word[10];
            my $destInfo = $word[12];
            my $duration = $word[14];
            my ($hour, $min, $sec) = split(':', $duration);
            my $duration = $hour * 3600 + $min * 60 + $sec;
            my $bytes = $word[16];
#           print(" t:$time, $proto, $sourceInfo, $destInfo, $duration, $bytes<BR> ");
            my ( $sourceInt, $rest ) = split(':', $sourceInfo);
            my ( $sourceIp, $sourcePort ) = split('/', $rest);
            my ( $destInt, $rest ) = split(':', $destInfo);
            my ( $destIp, $destPort) = split('/', $rest);
            my $reverse = "-";
            # this is not 100% bullet proof, but it will correct order errors in CatOS syslog reporting.
            # Temporary disabled due to mis interpretations on correct reporting fw's
            # will need to enable this if new reporting errors occur.
#           if (( "$knownProts{$sourcePort}" eq "known" ) or ((  $sourcePort < 1024 ) and ( "$sourcePort" ne "0" )) and ( "$destPort" ne "$sourcePort" )) {
#             ( $sourceIp, $sourcePort, $destIp, $destPort ) = ( $destIp, $destPort, $sourceIp, $sourcePort );
#             $reverse = "rev";
#           }
            my $longSourceIp = longIp($sourceIp);
            my $longDestIp = longIp($destIp);
            my $longDestPort = sprintf("%05d", $destPort);
#           print(" $sourceIp, $sourcePort - $destIp, $destPort<BR> ");
            if ( ! -d "$baseDir/source/$longSourceIp" ) {  mkdir "$baseDir/source/$longSourceIp"; }
            if ( ! -d "$baseDir/dest/$longDestIp" ) { mkdir "$baseDir/dest/$longDestIp"; }
            if ( ! -d "$baseDir/port/$longDestPort-$proto" ) { mkdir "$baseDir/port/$longDestPort-$proto"; }
            my $found;
            my $baseFile = "$longSourceIp-$longDestIp-$proto-$longDestPort";
            if ( ! -f "$baseDir/source/$longSourceIp/$baseFile" ) { $found = "no"; }
            printFileLine("$baseDir/source/$longSourceIp/$baseFile","append","asa-teardown $date $time $sourceIp $sourcePort $destIp $destPort $proto $duration $bytes $reverse $sourceInt\n");
            if ( "$found" eq "no" ) {
              touchFile("$baseDir/dest/$longDestIp/$baseFile");
              touchFile("$baseDir/port/$longDestPort-$proto/$baseFile");
            }
          }
          $num++;
          if ( $num > 100 ) {
            $num = 0;
            $centos++;
            print(".");
            if ( $centos > 10 ) {
              $centos = 0;
              $total++;
              print(" $total ");
            }
          }
        }
        close IN;
      }
      if ( -d "$baseDir.old" ) {
        print("<BR>Removing old data...");
        system(" rm -fR $baseDir.old & ");
      }
      print("done.");
#     print("</PRE>");
    }
  } else {
    print("syslogDir: $syslogDir, device: $device. Oops, tool not yet ready, be patient for the next release, working on it.");
  }
  print("<P>");
# SIMtrafficAnalyserDir
}


sub processTeardown {
  my $device = "@_[0]";
  my $date = "@_[1]";
  my $time = "@_[2]";
  my $message = "@_[3]";
  # ------------------------------------
  my @word = split(' ', $message);
  if (( "$word[1]" eq "Teardown" ) and (( "$word[2]" eq "TCP" ) or ( "$word[2]" eq "UDP" )) and ( "$word[12]" ne "0" )) {
    my $proto = lc($word[2]);
    my $sourceInfo = $word[6];
    my $destInfo = $word[8];
    my $duration = $word[10];
    my ($hour, $min, $sec) = split(':', $duration);
    my $duration = $hour * 3600 + $min * 60 + $sec;
    my $bytes = $word[12];
#   print(" t:$time, $proto, $sourceInfo, $destInfo, $duration, $bytes<BR> ");
    my ( $sourceInt, $rest ) = split(':', $sourceInfo);
    my ( $sourceIp, $sourcePort ) = split('/', $rest);
    my ( $destInt, $rest ) = split(':', $destInfo);
    my ( $destIp, $destPort) = split('/', $rest);
    my $reverse = "-";
    # this is not 100% bullet proof, but it will correct order errors in CatOS syslog reporting.
    if (( "$knownProts{$sourcePort}" eq "known" ) or ((  $sourcePort < 1024 ) and ( "$sourcePort" ne "0" )) and ( "$destPort" ne "$sourcePort" )) {
      ( $sourceIp, $sourcePort, $destIp, $destPort ) = ( $destIp, $destPort, $sourceIp, $sourcePort );
      $reverse = "rev";
    }
    my $longSourceIp = longIp($sourceIp);
    my $longDestIp = longIp($destIp);
    my $longDestPort = sprintf("%05d", $destPort);
#   print(" $sourceIp, $sourcePort - $destIp, $destPort<BR> ");
    my $logdate = printDate( time, "yyyymmdd" );
    my $baseDir = "$SIMparam{'SIMtrafficAnalyserDir'}/asa-$logdate/$device";
    testMkDir( "$baseDir/source/$longSourceIp" );  
    testMkDir( "$baseDir/dest/$longDestIp" );
    testMkDir( "$baseDir/port/$longDestPort-$proto" );
    my $found;
    my $baseFile = "$longSourceIp-$longDestIp-$proto-$longDestPort";
    if ( ! -f "$baseDir/source/$longSourceIp/$baseFile" ) { $found = "no"; }
    printFileLine("$baseDir/source/$longSourceIp/$baseFile","append","asa-teardown $date $time $sourceIp $sourcePort $destIp $destPort $proto $duration $bytes $reverse $sourceInt\n");
    if ( "$found" eq "no" ) {
      touchFile("$baseDir/dest/$longDestIp/$baseFile");
      touchFile("$baseDir/port/$longDestPort-$proto/$baseFile");
    }
  }
}

# 1 required for complete code of module

1;
